package com.sghd.football.utils;

import com.sghd.common.socket.core.ResultCallback;
import com.sghd.common.socket.handler.ResponseResultCallback;
import com.sghd.common.utils.json.JsonUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 拦截facade层
 * 要求日志级别开启 debug模式
 * @author 王创辉
 * @date 2016-05-21
 */
@Aspect
public class VerifyFilter {
    private Logger logger = LoggerFactory.getLogger(ResponseResultCallback.class);
    private ConcurrentMap<Method, MethodDefine> cache = new ConcurrentHashMap<>();
    //获取参数名称
    private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();

    @Around("execution(* com.sghd.football.module..*Facade*.*(..))")
    public Object execute(ProceedingJoinPoint pjp) throws Throwable {
        Signature sign = pjp.getSignature();
        if (!(sign instanceof MethodSignature)) {
            return pjp.proceed(pjp.getArgs());
        }
        if (!logger.isDebugEnabled())
            return pjp.proceed(pjp.getArgs());

        Method method = ((MethodSignature) sign).getMethod();
        MethodDefine define = cache.get(method);
        if (define == null) {
            synchronized (this) {
                define = cache.get(method);
                if (define == null) {
                    String[] argNames = parameterNameDiscoverer.getParameterNames(method);
                    boolean callback = isCallback(method);
                    define = new MethodDefine(argNames, callback);
                    cache.putIfAbsent(method, define);
                }
            }
        }
        Object[] args = pjp.getArgs();
        StringBuilder sb = new StringBuilder();
        String methodName = method.getName();
        String className = method.getDeclaringClass().getSimpleName();
        sb.append("类名=").append(className);
        sb.append(",方法名=").append(methodName);
        sb.append(",参数：");
        String temp = "";
        String[] argNames = define.getArgNames();
        for (int i = 0; i < argNames.length; i++) {
            sb.append(argNames[i]).append("=");
            try {
                Object param = args[i];
                if (param instanceof String) {
                    temp = (String) param;
                } else {
                    temp = JsonUtils.object2String(param);
                }
            } catch (Exception e) {
                temp = "???";
            }
            sb.append(temp).append(",");
        }
        System.err.println(sb.toString());
        Object ret = pjp.proceed(args);
        if(!define.isCallBack){
            sb = new StringBuilder();
            sb.append("方法").append(methodName).append("返回结果：");
            try {
                temp = JsonUtils.object2String(ret);
            } catch (Exception e) {
                temp = "###";
            }
            sb.append(temp);
            System.err.println(sb.toString());
        }
        return ret;
    }

    private boolean isCallback(Method method) {
        for (Class<?> clz : method.getParameterTypes()) {
            if (ResultCallback.class.isAssignableFrom(clz)) {
                return true;
            }
        }
        return false;
    }

    private class MethodDefine {
        private String[] argNames;
        private boolean isCallBack;

        public MethodDefine(String[] argNames, boolean isCallBack) {
            this.argNames = argNames;
            this.isCallBack = isCallBack;
        }

        public String[] getArgNames() {
            return argNames;
        }
    }
}
